{
    "cells": [
        {
            "cell_type": "code",
            "execution_count": 1,
            "metadata": {},
            "outputs": [],
            "source": [
                "import csv\n",
                "\n",
                "import numpy as np\n",
                "import tensorflow as tf\n",
                "from sklearn.model_selection import train_test_split\n",
                "\n",
                "RANDOM_SEED = 42"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "# Dataset Specification"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "metadata": {},
            "outputs": [],
            "source": [
                "dataset = 'model/keypoint_classifier/keypoint.csv'\n",
                "model_save_path = 'model/keypoint_classifier/keypoint_classifier.hdf5'"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "# Number of Classes Setting"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 3,
            "metadata": {},
            "outputs": [],
            "source": [
                "NUM_CLASSES = 3"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "# Training Data Loading"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": []
        },
        {
            "cell_type": "code",
            "execution_count": 4,
            "metadata": {},
            "outputs": [],
            "source": [
                "X_dataset = np.loadtxt(dataset, delimiter=',', dtype='float32', usecols=list(range(1, (21 * 2) + 1)))"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 5,
            "metadata": {},
            "outputs": [],
            "source": [
                "y_dataset = np.loadtxt(dataset, delimiter=',', dtype='int32', usecols=(0))"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 6,
            "metadata": {},
            "outputs": [],
            "source": [
                "X_train, X_test, y_train, y_test = train_test_split(X_dataset, y_dataset, train_size=0.75, random_state=RANDOM_SEED)"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "# Model Architecture"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 7,
            "metadata": {},
            "outputs": [],
            "source": [
                "model = tf.keras.models.Sequential(["    # Neural Network Model Structure\n","    tf.keras.layers.Input((21 * 2, )),\n","    tf.keras.layers.Dropout(0.2),\n","    tf.keras.layers.Dense(20, activation='relu'),\n","    tf.keras.layers.Dropout(0.4),\n","    tf.keras.layers.Dense(10, activation='relu'),\n","    tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')\n","
            ])"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 8,
        "metadata": {},
        "outputs": [
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Model: \"sequential\"\n",
                    "_________________________________________________________________\n",
                    "Layer (type)                 Output Shape              Param #   \n",
                    "=================================================================\n",
                    "dropout (Dropout)            (None, 42)                0         \n",
                    "_________________________________________________________________\n",
                    "dense (Dense)                (None, 20)                860       \n",
                    "_________________________________________________________________\n",
                    "dropout_1 (Dropout)          (None, 20)                0         \n",
                    "_________________________________________________________________\n",
                    "dense_1 (Dense)              (None, 10)                210       \n",
                    "_________________________________________________________________\n",
                    "dense_2 (Dense)              (None, 3)                 33        \n",
                    "=================================================================\n",
                    "Total params: 1,103\n",
                    "Trainable params: 1,103\n",
                    "Non-trainable params: 0\n",
                    "_________________________________________________________________\n"
                ]
            }
        ],
        "source": [
            "model.summary()  # tf.keras.utils.plot_model(model, show_shapes=True)"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 9,
        "metadata": {},
        "outputs": [],
        "source": [
            "# Callback for Model Checkpoint\n",
            "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
            "    model_save_path, verbose=1, save_weights_only=False)\n",
            "# Callback for Early Stopping\n",
            "es_callback = tf.keras.callbacks.EarlyStopping(patience=20, verbose=1)"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 10,
        "metadata": {},
        "outputs": [],
        "source": [
            "# Model Compilation\n",
            "model.compile(\n",
            "    optimizer='adam',\n",
            "    loss='sparse_categorical_crossentropy',\n",
            "    metrics=['accuracy']\n",
            ")"
        ]
    },
    {
        "cell_type": "markdown",
        "metadata": {},
        "source": [
            "# Model Training"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 11,
        "metadata": {
            "scrolled": true
        },
        "outputs": [
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Epoch 1/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 1.1295 - accuracy: 0.3203\n",
                    "Epoch 00001: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 11ms/step - loss: 1.1004 - accuracy: 0.3602 - val_loss: 1.0431 - val_accuracy: 0.5220\n",
                    "Epoch 2/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 1.0440 - accuracy: 0.4844\n",
                    "Epoch 00002: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 1.0503 - accuracy: 0.4297 - val_loss: 0.9953 - val_accuracy: 0.6397\n",
                    "Epoch 3/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 1.0043 - accuracy: 0.5312\n",
                    "Epoch 00003: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 1.0210 - accuracy: 0.4582 - val_loss: 0.9545 - val_accuracy: 0.6523\n",
                    "Epoch 4/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.9503 - accuracy: 0.5625\n",
                    "Epoch 00004: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.9906 - accuracy: 0.5022 - val_loss: 0.9168 - val_accuracy: 0.6721\n",
                    "Epoch 5/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.9562 - accuracy: 0.5469\n",
                    "Epoch 00005: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.9654 - accuracy: 0.5340 - val_loss: 0.8791 - val_accuracy: 0.7017\n",
                    "Epoch 6/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.9184 - accuracy: 0.5938\n",
                    "Epoch 00006: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.9256 - accuracy: 0.5577 - val_loss: 0.8344 - val_accuracy: 0.7269\n",
                    "Epoch 7/1000\n",
                    "27/27 [==============================] - ETA: 0s - loss: 0.9050 - accuracy: 0.5715\n",
                    "Epoch 00007: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.9050 - accuracy: 0.5715 - val_loss: 0.7887 - val_accuracy: 0.7646\n",
                    "Epoch 8/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.9135 - accuracy: 0.5547\n",
                    "Epoch 00008: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.8642 - accuracy: 0.5993 - val_loss: 0.7414 - val_accuracy: 0.7996\n",
                    "Epoch 9/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.8002 - accuracy: 0.6172\n",
                    "Epoch 00009: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.8258 - accuracy: 0.6263 - val_loss: 0.6881 - val_accuracy: 0.8149\n",
                    "Epoch 10/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.8056 - accuracy: 0.6328\n",
                    "Epoch 00010: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.8008 - accuracy: 0.6341 - val_loss: 0.6461 - val_accuracy: 0.8239\n",
                    "Epoch 11/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.7746 - accuracy: 0.6719\n",
                    "Epoch 00011: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.7771 - accuracy: 0.6491 - val_loss: 0.6143 - val_accuracy: 0.8266\n",
                    "Epoch 12/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.7242 - accuracy: 0.7109\n",
                    "Epoch 00012: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.7490 - accuracy: 0.6650 - val_loss: 0.5740 - val_accuracy: 0.8320\n",
                    "Epoch 13/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.8363 - accuracy: 0.6328\n",
                    "Epoch 00013: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.7397 - accuracy: 0.6731 - val_loss: 0.5465 - val_accuracy: 0.8446\n",
                    "Epoch 14/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.7634 - accuracy: 0.6172\n",
                    "Epoch 00014: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.7190 - accuracy: 0.6883 - val_loss: 0.5202 - val_accuracy: 0.8589\n",
                    "Epoch 15/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.6699 - accuracy: 0.6875\n",
                    "Epoch 00015: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.7077 - accuracy: 0.6973 - val_loss: 0.4944 - val_accuracy: 0.8652\n",
                    "Epoch 16/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.6447 - accuracy: 0.7500\n",
                    "Epoch 00016: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.6903 - accuracy: 0.6928 - val_loss: 0.4781 - val_accuracy: 0.8805\n",
                    "Epoch 17/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.7165 - accuracy: 0.6875\n",
                    "Epoch 00017: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.6919 - accuracy: 0.6973 - val_loss: 0.4696 - val_accuracy: 0.8895\n",
                    "Epoch 18/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.6268 - accuracy: 0.7422\n",
                    "Epoch 00018: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.6498 - accuracy: 0.7303 - val_loss: 0.4440 - val_accuracy: 0.8967\n",
                    "Epoch 19/1000\n",
                    "27/27 [==============================] - ETA: 0s - loss: 0.6499 - accuracy: 0.7261\n",
                    "Epoch 00019: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.6499 - accuracy: 0.7261 - val_loss: 0.4254 - val_accuracy: 0.9039\n",
                    "Epoch 20/1000\n",
                    "26/27 [===========================>..] - ETA: 0s - loss: 0.6386 - accuracy: 0.7236\n",
                    "Epoch 00020: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.6415 - accuracy: 0.7228 - val_loss: 0.4082 - val_accuracy: 0.9093\n",
                    "Epoch 21/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5631 - accuracy: 0.7500\n",
                    "Epoch 00021: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.6484 - accuracy: 0.7180 - val_loss: 0.4114 - val_accuracy: 0.9173\n",
                    "Epoch 22/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5775 - accuracy: 0.7812\n",
                    "Epoch 00022: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.6154 - accuracy: 0.7480 - val_loss: 0.3907 - val_accuracy: 0.9218\n",
                    "Epoch 23/1000\n",
                    "25/27 [==========================>...] - ETA: 0s - loss: 0.5967 - accuracy: 0.7588\n",
                    "Epoch 00023: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.5971 - accuracy: 0.7582 - val_loss: 0.3763 - val_accuracy: 0.9227\n",
                    "Epoch 24/1000\n",
                    "26/27 [===========================>..] - ETA: 0s - loss: 0.6064 - accuracy: 0.7569\n",
                    "Epoch 00024: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.6066 - accuracy: 0.7567 - val_loss: 0.3714 - val_accuracy: 0.9254\n",
                    "Epoch 25/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.6211 - accuracy: 0.7422\n",
                    "Epoch 00025: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 7ms/step - loss: 0.5954 - accuracy: 0.7579 - val_loss: 0.3611 - val_accuracy: 0.9353\n",
                    "Epoch 26/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5621 - accuracy: 0.7812\n",
                    "Epoch 00026: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5818 - accuracy: 0.7737 - val_loss: 0.3498 - val_accuracy: 0.9380\n",
                    "Epoch 27/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.6431 - accuracy: 0.7500\n",
                    "Epoch 00027: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5882 - accuracy: 0.7648 - val_loss: 0.3355 - val_accuracy: 0.9416\n"
                ]
            },
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Epoch 28/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5633 - accuracy: 0.8203\n",
                    "Epoch 00028: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5746 - accuracy: 0.7702 - val_loss: 0.3273 - val_accuracy: 0.9425\n",
                    "Epoch 29/1000\n",
                    "27/27 [==============================] - ETA: 0s - loss: 0.5856 - accuracy: 0.7651\n",
                    "Epoch 00029: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.5856 - accuracy: 0.7651 - val_loss: 0.3237 - val_accuracy: 0.9434\n",
                    "Epoch 30/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5524 - accuracy: 0.7812\n",
                    "Epoch 00030: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5576 - accuracy: 0.7788 - val_loss: 0.3203 - val_accuracy: 0.9452\n",
                    "Epoch 31/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5643 - accuracy: 0.7578\n",
                    "Epoch 00031: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5450 - accuracy: 0.7773 - val_loss: 0.3111 - val_accuracy: 0.9443\n",
                    "Epoch 32/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5507 - accuracy: 0.7812\n",
                    "Epoch 00032: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 6ms/step - loss: 0.5574 - accuracy: 0.7860 - val_loss: 0.3017 - val_accuracy: 0.9434\n",
                    "Epoch 33/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5302 - accuracy: 0.8125\n",
                    "Epoch 00033: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5444 - accuracy: 0.7905 - val_loss: 0.2917 - val_accuracy: 0.9479\n",
                    "Epoch 34/1000\n",
                    "27/27 [==============================] - ETA: 0s - loss: 0.5421 - accuracy: 0.7848\n",
                    "Epoch 00034: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.5421 - accuracy: 0.7848 - val_loss: 0.2863 - val_accuracy: 0.9470\n",
                    "Epoch 35/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4633 - accuracy: 0.8125\n",
                    "Epoch 00035: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5331 - accuracy: 0.7980 - val_loss: 0.2804 - val_accuracy: 0.9506\n",
                    "Epoch 36/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5972 - accuracy: 0.7812\n",
                    "Epoch 00036: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5255 - accuracy: 0.7968 - val_loss: 0.2774 - val_accuracy: 0.9479\n",
                    "Epoch 37/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5851 - accuracy: 0.7578\n",
                    "Epoch 00037: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5284 - accuracy: 0.7947 - val_loss: 0.2681 - val_accuracy: 0.9497\n",
                    "Epoch 38/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4775 - accuracy: 0.7812\n",
                    "Epoch 00038: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5143 - accuracy: 0.7995 - val_loss: 0.2678 - val_accuracy: 0.9479\n",
                    "Epoch 39/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5495 - accuracy: 0.7812\n",
                    "Epoch 00039: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5250 - accuracy: 0.7935 - val_loss: 0.2657 - val_accuracy: 0.9470\n",
                    "Epoch 40/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5244 - accuracy: 0.8203\n",
                    "Epoch 00040: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5195 - accuracy: 0.8001 - val_loss: 0.2606 - val_accuracy: 0.9524\n",
                    "Epoch 41/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.6996 - accuracy: 0.6953\n",
                    "Epoch 00041: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5304 - accuracy: 0.7956 - val_loss: 0.2572 - val_accuracy: 0.9515\n",
                    "Epoch 42/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4843 - accuracy: 0.8281\n",
                    "Epoch 00042: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5115 - accuracy: 0.8091 - val_loss: 0.2513 - val_accuracy: 0.9524\n",
                    "Epoch 43/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3830 - accuracy: 0.8594\n",
                    "Epoch 00043: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4939 - accuracy: 0.8133 - val_loss: 0.2423 - val_accuracy: 0.9551\n",
                    "Epoch 44/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4531 - accuracy: 0.7969\n",
                    "Epoch 00044: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4969 - accuracy: 0.8094 - val_loss: 0.2437 - val_accuracy: 0.9497\n",
                    "Epoch 45/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5198 - accuracy: 0.7812\n",
                    "Epoch 00045: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4961 - accuracy: 0.8106 - val_loss: 0.2441 - val_accuracy: 0.9533\n",
                    "Epoch 46/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5912 - accuracy: 0.7812\n",
                    "Epoch 00046: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4816 - accuracy: 0.8271 - val_loss: 0.2482 - val_accuracy: 0.9542\n",
                    "Epoch 47/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5292 - accuracy: 0.8047\n",
                    "Epoch 00047: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4789 - accuracy: 0.8127 - val_loss: 0.2313 - val_accuracy: 0.9569\n",
                    "Epoch 48/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4428 - accuracy: 0.8125\n",
                    "Epoch 00048: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4901 - accuracy: 0.8079 - val_loss: 0.2319 - val_accuracy: 0.9560\n",
                    "Epoch 49/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4565 - accuracy: 0.8281\n",
                    "Epoch 00049: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4893 - accuracy: 0.8154 - val_loss: 0.2300 - val_accuracy: 0.9533\n",
                    "Epoch 50/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5185 - accuracy: 0.7812\n",
                    "Epoch 00050: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.5079 - accuracy: 0.8112 - val_loss: 0.2386 - val_accuracy: 0.9524\n",
                    "Epoch 51/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4280 - accuracy: 0.8203\n",
                    "Epoch 00051: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4692 - accuracy: 0.8205 - val_loss: 0.2332 - val_accuracy: 0.9578\n",
                    "Epoch 52/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5299 - accuracy: 0.8203\n",
                    "Epoch 00052: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4907 - accuracy: 0.8145 - val_loss: 0.2336 - val_accuracy: 0.9569\n",
                    "Epoch 53/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5856 - accuracy: 0.7969\n",
                    "Epoch 00053: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4882 - accuracy: 0.8181 - val_loss: 0.2306 - val_accuracy: 0.9605\n",
                    "Epoch 54/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4466 - accuracy: 0.8047\n",
                    "Epoch 00054: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4641 - accuracy: 0.8235 - val_loss: 0.2218 - val_accuracy: 0.9596\n"
                ]
            },
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Epoch 55/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3760 - accuracy: 0.8672\n",
                    "Epoch 00055: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4630 - accuracy: 0.8241 - val_loss: 0.2242 - val_accuracy: 0.9578\n",
                    "Epoch 56/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4607 - accuracy: 0.7734\n",
                    "Epoch 00056: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4546 - accuracy: 0.8277 - val_loss: 0.2168 - val_accuracy: 0.9605\n",
                    "Epoch 57/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4946 - accuracy: 0.7969\n",
                    "Epoch 00057: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4675 - accuracy: 0.8214 - val_loss: 0.2211 - val_accuracy: 0.9578\n",
                    "Epoch 58/1000\n",
                    "25/27 [==========================>...] - ETA: 0s - loss: 0.4393 - accuracy: 0.8334\n",
                    "Epoch 00058: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.4418 - accuracy: 0.8325 - val_loss: 0.2115 - val_accuracy: 0.9632\n",
                    "Epoch 59/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4987 - accuracy: 0.7969\n",
                    "Epoch 00059: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4646 - accuracy: 0.8217 - val_loss: 0.2116 - val_accuracy: 0.9596\n",
                    "Epoch 60/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4904 - accuracy: 0.7812\n",
                    "Epoch 00060: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4576 - accuracy: 0.8232 - val_loss: 0.2108 - val_accuracy: 0.9569\n",
                    "Epoch 61/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5147 - accuracy: 0.8281\n",
                    "Epoch 00061: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4646 - accuracy: 0.8253 - val_loss: 0.2174 - val_accuracy: 0.9587\n",
                    "Epoch 62/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3386 - accuracy: 0.8750\n",
                    "Epoch 00062: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4433 - accuracy: 0.8310 - val_loss: 0.2145 - val_accuracy: 0.9560\n",
                    "Epoch 63/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4222 - accuracy: 0.8594\n",
                    "Epoch 00063: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4624 - accuracy: 0.8283 - val_loss: 0.2099 - val_accuracy: 0.9569\n",
                    "Epoch 64/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4376 - accuracy: 0.8203\n",
                    "Epoch 00064: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4601 - accuracy: 0.8235 - val_loss: 0.2075 - val_accuracy: 0.9641\n",
                    "Epoch 65/1000\n",
                    "27/27 [==============================] - ETA: 0s - loss: 0.4676 - accuracy: 0.8265\n",
                    "Epoch 00065: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4676 - accuracy: 0.8265 - val_loss: 0.2172 - val_accuracy: 0.9551\n",
                    "Epoch 66/1000\n",
                    "26/27 [===========================>..] - ETA: 0s - loss: 0.4434 - accuracy: 0.8368\n",
                    "Epoch 00066: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 1s 20ms/step - loss: 0.4429 - accuracy: 0.8370 - val_loss: 0.2154 - val_accuracy: 0.9578\n",
                    "Epoch 67/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4827 - accuracy: 0.8125\n",
                    "Epoch 00067: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4434 - accuracy: 0.8358 - val_loss: 0.2090 - val_accuracy: 0.9587\n",
                    "Epoch 68/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5810 - accuracy: 0.7656\n",
                    "Epoch 00068: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4892 - accuracy: 0.8049 - val_loss: 0.2160 - val_accuracy: 0.9578\n",
                    "Epoch 69/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4375 - accuracy: 0.7812\n",
                    "Epoch 00069: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4597 - accuracy: 0.8250 - val_loss: 0.2100 - val_accuracy: 0.9605\n",
                    "Epoch 70/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3782 - accuracy: 0.8359\n",
                    "Epoch 00070: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4408 - accuracy: 0.8349 - val_loss: 0.2087 - val_accuracy: 0.9596\n",
                    "Epoch 71/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4578 - accuracy: 0.8438\n",
                    "Epoch 00071: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4425 - accuracy: 0.8355 - val_loss: 0.2075 - val_accuracy: 0.9587\n",
                    "Epoch 72/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4267 - accuracy: 0.8438\n",
                    "Epoch 00072: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4581 - accuracy: 0.8292 - val_loss: 0.2059 - val_accuracy: 0.9623\n",
                    "Epoch 73/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4450 - accuracy: 0.8750\n",
                    "Epoch 00073: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4508 - accuracy: 0.8403 - val_loss: 0.2083 - val_accuracy: 0.9614\n",
                    "Epoch 74/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3858 - accuracy: 0.8906\n",
                    "Epoch 00074: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4472 - accuracy: 0.8361 - val_loss: 0.2043 - val_accuracy: 0.9650\n",
                    "Epoch 75/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4439 - accuracy: 0.8359\n",
                    "Epoch 00075: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4515 - accuracy: 0.8325 - val_loss: 0.2138 - val_accuracy: 0.9632\n",
                    "Epoch 76/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3983 - accuracy: 0.8203\n",
                    "Epoch 00076: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4462 - accuracy: 0.8334 - val_loss: 0.2065 - val_accuracy: 0.9623\n",
                    "Epoch 77/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5020 - accuracy: 0.8047\n",
                    "Epoch 00077: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4325 - accuracy: 0.8388 - val_loss: 0.2061 - val_accuracy: 0.9605\n",
                    "Epoch 78/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3215 - accuracy: 0.8672\n",
                    "Epoch 00078: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4394 - accuracy: 0.8391 - val_loss: 0.2054 - val_accuracy: 0.9578\n",
                    "Epoch 79/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4025 - accuracy: 0.8359\n",
                    "Epoch 00079: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4370 - accuracy: 0.8310 - val_loss: 0.2031 - val_accuracy: 0.9605\n",
                    "Epoch 80/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4505 - accuracy: 0.8125\n",
                    "Epoch 00080: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4419 - accuracy: 0.8340 - val_loss: 0.2010 - val_accuracy: 0.9596\n",
                    "Epoch 81/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5287 - accuracy: 0.7891\n",
                    "Epoch 00081: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4369 - accuracy: 0.8304 - val_loss: 0.2081 - val_accuracy: 0.9578\n"
                ]
            },
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Epoch 82/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5132 - accuracy: 0.8047\n",
                    "Epoch 00082: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4360 - accuracy: 0.8460 - val_loss: 0.2045 - val_accuracy: 0.9605\n",
                    "Epoch 83/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4239 - accuracy: 0.8125\n",
                    "Epoch 00083: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4511 - accuracy: 0.8313 - val_loss: 0.1984 - val_accuracy: 0.9605\n",
                    "Epoch 84/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4853 - accuracy: 0.8203\n",
                    "Epoch 00084: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4357 - accuracy: 0.8304 - val_loss: 0.2024 - val_accuracy: 0.9623\n",
                    "Epoch 85/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4782 - accuracy: 0.8125\n",
                    "Epoch 00085: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4320 - accuracy: 0.8424 - val_loss: 0.2015 - val_accuracy: 0.9587\n",
                    "Epoch 86/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3985 - accuracy: 0.8828\n",
                    "Epoch 00086: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4422 - accuracy: 0.8349 - val_loss: 0.2087 - val_accuracy: 0.9587\n",
                    "Epoch 87/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4810 - accuracy: 0.8359\n",
                    "Epoch 00087: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4393 - accuracy: 0.8316 - val_loss: 0.2105 - val_accuracy: 0.9605\n",
                    "Epoch 88/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4819 - accuracy: 0.8125\n",
                    "Epoch 00088: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4381 - accuracy: 0.8400 - val_loss: 0.2070 - val_accuracy: 0.9623\n",
                    "Epoch 89/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5002 - accuracy: 0.8281\n",
                    "Epoch 00089: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4428 - accuracy: 0.8343 - val_loss: 0.2044 - val_accuracy: 0.9605\n",
                    "Epoch 90/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3314 - accuracy: 0.9062\n",
                    "Epoch 00090: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4156 - accuracy: 0.8406 - val_loss: 0.2026 - val_accuracy: 0.9578\n",
                    "Epoch 91/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3850 - accuracy: 0.8594\n",
                    "Epoch 00091: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4125 - accuracy: 0.8439 - val_loss: 0.2058 - val_accuracy: 0.9551\n",
                    "Epoch 92/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4976 - accuracy: 0.7734\n",
                    "Epoch 00092: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4217 - accuracy: 0.8415 - val_loss: 0.1999 - val_accuracy: 0.9623\n",
                    "Epoch 93/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4155 - accuracy: 0.8516\n",
                    "Epoch 00093: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4166 - accuracy: 0.8412 - val_loss: 0.1947 - val_accuracy: 0.9614\n",
                    "Epoch 94/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3642 - accuracy: 0.8750\n",
                    "Epoch 00094: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4204 - accuracy: 0.8418 - val_loss: 0.2008 - val_accuracy: 0.9569\n",
                    "Epoch 95/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3773 - accuracy: 0.8594\n",
                    "Epoch 00095: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 4ms/step - loss: 0.4171 - accuracy: 0.8421 - val_loss: 0.1945 - val_accuracy: 0.9596\n",
                    "Epoch 96/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4086 - accuracy: 0.8672\n",
                    "Epoch 00096: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4124 - accuracy: 0.8520 - val_loss: 0.1930 - val_accuracy: 0.9614\n",
                    "Epoch 97/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.2914 - accuracy: 0.8906\n",
                    "Epoch 00097: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4303 - accuracy: 0.8367 - val_loss: 0.1958 - val_accuracy: 0.9569\n",
                    "Epoch 98/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4562 - accuracy: 0.8672\n",
                    "Epoch 00098: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4191 - accuracy: 0.8400 - val_loss: 0.1950 - val_accuracy: 0.9596\n",
                    "Epoch 99/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3967 - accuracy: 0.8438\n",
                    "Epoch 00099: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4260 - accuracy: 0.8418 - val_loss: 0.2044 - val_accuracy: 0.9551\n",
                    "Epoch 100/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4173 - accuracy: 0.8516\n",
                    "Epoch 00100: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4200 - accuracy: 0.8442 - val_loss: 0.2066 - val_accuracy: 0.9560\n",
                    "Epoch 101/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3892 - accuracy: 0.8438\n",
                    "Epoch 00101: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4245 - accuracy: 0.8418 - val_loss: 0.2058 - val_accuracy: 0.9578\n",
                    "Epoch 102/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.2965 - accuracy: 0.8984\n",
                    "Epoch 00102: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4100 - accuracy: 0.8445 - val_loss: 0.2093 - val_accuracy: 0.9578\n",
                    "Epoch 103/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4241 - accuracy: 0.8125\n",
                    "Epoch 00103: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4189 - accuracy: 0.8403 - val_loss: 0.1928 - val_accuracy: 0.9659\n",
                    "Epoch 104/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.6486 - accuracy: 0.7891\n",
                    "Epoch 00104: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4223 - accuracy: 0.8424 - val_loss: 0.1964 - val_accuracy: 0.9596\n",
                    "Epoch 105/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4589 - accuracy: 0.8281\n",
                    "Epoch 00105: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4199 - accuracy: 0.8418 - val_loss: 0.1971 - val_accuracy: 0.9623\n",
                    "Epoch 106/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4395 - accuracy: 0.8203\n",
                    "Epoch 00106: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4028 - accuracy: 0.8511 - val_loss: 0.1912 - val_accuracy: 0.9641\n",
                    "Epoch 107/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4061 - accuracy: 0.8594\n",
                    "Epoch 00107: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4093 - accuracy: 0.8556 - val_loss: 0.1854 - val_accuracy: 0.9668\n",
                    "Epoch 108/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4142 - accuracy: 0.8438\n",
                    "Epoch 00108: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4249 - accuracy: 0.8367 - val_loss: 0.2008 - val_accuracy: 0.9614\n"
                ]
            },
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Epoch 109/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5373 - accuracy: 0.7969\n",
                    "Epoch 00109: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4198 - accuracy: 0.8379 - val_loss: 0.1955 - val_accuracy: 0.9659\n",
                    "Epoch 110/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3872 - accuracy: 0.8281\n",
                    "Epoch 00110: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4077 - accuracy: 0.8505 - val_loss: 0.2020 - val_accuracy: 0.9614\n",
                    "Epoch 111/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3474 - accuracy: 0.8828\n",
                    "Epoch 00111: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4132 - accuracy: 0.8433 - val_loss: 0.1984 - val_accuracy: 0.9632\n",
                    "Epoch 112/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4205 - accuracy: 0.8672\n",
                    "Epoch 00112: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4182 - accuracy: 0.8397 - val_loss: 0.1973 - val_accuracy: 0.9614\n",
                    "Epoch 113/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4995 - accuracy: 0.8125\n",
                    "Epoch 00113: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4042 - accuracy: 0.8478 - val_loss: 0.1922 - val_accuracy: 0.9650\n",
                    "Epoch 114/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3640 - accuracy: 0.8750\n",
                    "Epoch 00114: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4072 - accuracy: 0.8430 - val_loss: 0.1868 - val_accuracy: 0.9596\n",
                    "Epoch 115/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5042 - accuracy: 0.8203\n",
                    "Epoch 00115: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.3999 - accuracy: 0.8535 - val_loss: 0.1966 - val_accuracy: 0.9605\n",
                    "Epoch 116/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.5355 - accuracy: 0.7422\n",
                    "Epoch 00116: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4174 - accuracy: 0.8433 - val_loss: 0.1919 - val_accuracy: 0.9659\n",
                    "Epoch 117/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3729 - accuracy: 0.8750\n",
                    "Epoch 00117: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4101 - accuracy: 0.8451 - val_loss: 0.1932 - val_accuracy: 0.9578\n",
                    "Epoch 118/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3193 - accuracy: 0.8828\n",
                    "Epoch 00118: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4260 - accuracy: 0.8379 - val_loss: 0.1865 - val_accuracy: 0.9641\n",
                    "Epoch 119/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3852 - accuracy: 0.8438\n",
                    "Epoch 00119: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.3797 - accuracy: 0.8622 - val_loss: 0.1900 - val_accuracy: 0.9677\n",
                    "Epoch 120/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3636 - accuracy: 0.8594\n",
                    "Epoch 00120: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4017 - accuracy: 0.8460 - val_loss: 0.1908 - val_accuracy: 0.9659\n",
                    "Epoch 121/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4521 - accuracy: 0.8359\n",
                    "Epoch 00121: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4023 - accuracy: 0.8538 - val_loss: 0.1935 - val_accuracy: 0.9659\n",
                    "Epoch 122/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4849 - accuracy: 0.8203\n",
                    "Epoch 00122: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4186 - accuracy: 0.8457 - val_loss: 0.1937 - val_accuracy: 0.9659\n",
                    "Epoch 123/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4021 - accuracy: 0.8516\n",
                    "Epoch 00123: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4156 - accuracy: 0.8478 - val_loss: 0.1907 - val_accuracy: 0.9632\n",
                    "Epoch 124/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3601 - accuracy: 0.8906\n",
                    "Epoch 00124: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.3948 - accuracy: 0.8550 - val_loss: 0.1862 - val_accuracy: 0.9605\n",
                    "Epoch 125/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.4446 - accuracy: 0.7891\n",
                    "Epoch 00125: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.4152 - accuracy: 0.8520 - val_loss: 0.1888 - val_accuracy: 0.9623\n",
                    "Epoch 126/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3733 - accuracy: 0.8438\n",
                    "Epoch 00126: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.3913 - accuracy: 0.8550 - val_loss: 0.1937 - val_accuracy: 0.9632\n",
                    "Epoch 127/1000\n",
                    " 1/27 [>.............................] - ETA: 0s - loss: 0.3000 - accuracy: 0.8828\n",
                    "Epoch 00127: saving model to model/keypoint_classifier\\keypoint_classifier.hdf5\n",
                    "27/27 [==============================] - 0s 3ms/step - loss: 0.3820 - accuracy: 0.8583 - val_loss: 0.1867 - val_accuracy: 0.9632\n",
                    "Epoch 00127: early stopping\n"
                ]
            },
            {
                "data": {
                    "text/plain": [
                        "<tensorflow.python.keras.callbacks.History at 0x2314aafaaf0>"
                    ]
                },
                "execution_count": 11,
                "metadata": {},
                "output_type": "execute_result"
            }
        ],
        "source": [
            "model.fit(\n",
            "    X_train,\n",
            "    y_train,\n",
            "    epochs=1000,\n",
            "    batch_size=128,\n",
            "    validation_data=(X_test, y_test),\n",
            "    callbacks=[cp_callback, es_callback]\n",
            ")"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 12,
        "metadata": {},
        "outputs": [
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "9/9 [==============================] - 0s 1ms/step - loss: 0.1867 - accuracy: 0.9632\n"
                ]
            }
        ],
        "source": [
            "# Model Evaluation\n",
            "val_loss, val_acc = model.evaluate(X_test, y_test, batch_size=128)"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 13,
        "metadata": {},
        "outputs": [],
        "source": [
            "# Load the saved model\n",
            "model = tf.keras.models.load_model(model_save_path)"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 14,
        "metadata": {},
        "outputs": [
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "[0.77297777 0.1697358  0.05728642]\n",
                    "0\n"
                ]
            }
        ],
        "source": [
            "# Inference Test\n",
            "predict_result = model.predict(np.array([X_test[0]]))\n",
            "print(np.squeeze(predict_result))\n",
            "print(np.argmax(np.squeeze(predict_result)))"
        ]
    },
    {
        "cell_type": "markdown",
        "metadata": {},
        "source": [
            "# Model Evaluation and Inference"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 15,
        "metadata": {},
        "outputs": [
            {
                "data": {
                    "image/png": "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",
                    "text/plain": [
                        "<Figure size 504x432 with 2 Axes>"
                    ]
                },
                "metadata": {
                    "needs_background": "light"
                },
                "output_type": "display_data"
            },
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Classification Report\n",
                    "              precision    recall  f1-score   support\n",
                    "\n",
                    "           0       1.00      0.99      0.99       410\n",
                    "           1       0.98      0.92      0.95       385\n",
                    "           2       0.91      0.99      0.95       318\n",
                    "\n",
                    "    accuracy                           0.96      1113\n",
                    "   macro avg       0.96      0.96      0.96      1113\n",
                    "weighted avg       0.96      0.96      0.96      1113\n",
                    "\n"
                ]
            }
        ],
        "source": [
            "import pandas as pd\n",
            "import seaborn as sns\n",
            "import matplotlib.pyplot as plt\n",
            "from sklearn.metrics import confusion_matrix, classification_report\n",
            "\n",
            "def print_confusion_matrix(y_true, y_pred, report=True):\n",
            "    labels = sorted(list(set(y_true)))\n",
            "    cmx_data = confusion_matrix(y_true, y_pred, labels=labels)\n",
            "    \n",
            "    df_cmx = pd.DataFrame(cmx_data, index=labels, columns=labels)\n",
            " \n",
            "    fig, ax = plt.subplots(figsize=(7, 6))\n",
            "    sns.heatmap(df_cmx, annot=True, fmt='g' ,square=False)\n",
            "    ax.set_ylim(len(set(y_true)), 0)\n",
            "    plt.show()\n",
            "    \n",
            "    if report:\n",
            "        print('Classification Report')\n",
            "        print(classification_report(y_test, y_pred))\n",
            "\n",
            "Y_pred = model.predict(X_test)\n",
            "y_pred = np.argmax(Y_pred, axis=1)\n",
            "\n",
            "print_confusion_matrix(y_test, y_pred)"
        ]
    },
    {
        "cell_type": "markdown",
        "metadata": {},
        "source": [
            "# Convert Model for TensorFlow Lite"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 16,
        "metadata": {},
        "outputs": [],
        "source": [
            "# Save as a model for inference only\n",
            "model.save(model_save_path, include_optimizer=False)"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 17,
        "metadata": {},
        "outputs": [
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "WARNING:tensorflow:From d:\\00.envs\\20201208_mediapipe\\lib\\site-packages\\tensorflow\\python\\training\\tracking\\tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.\n",
                    "Instructions for updating:\n",
                    "This property should not be used in TensorFlow 2.0, as updates are applied automatically.\n",
                    "WARNING:tensorflow:From d:\\00.envs\\20201208_mediapipe\\lib\\site-packages\\tensorflow\\python\\training\\tracking\\tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.\n",
                    "Instructions for updating:\n",
                    "This property should not be used in TensorFlow 2.0, as updates are applied automatically.\n",
                    "INFO:tensorflow:Assets written to: C:\\Users\\sihit\\AppData\\Local\\Temp\\tmpy2l6ipxu\\assets\n"
                ]
            },
            {
                "data": {
                    "text/plain": [
                        "6224"
                    ]
                },
                "execution_count": 17,
                "metadata": {},
                "output_type": "execute_result"
            }
        ],
        "source": [
            "# Convert the model (with quantization)\n",
            "tflite_save_path = 'model/keypoint_classifier/keypoint_classifier.tflite'\n",
            "\n",
            "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n",
            "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n",
            "tflite_quantized_model = converter.convert()\n",
            "\n",
            "open(tflite_save_path, 'wb').write(tflite_quantized_model)"
        ]
    },
    {
        "cell_type": "markdown",
        "metadata": {},
        "source": [
            "# Inference Test"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 18,
        "metadata": {},
        "outputs": [],
        "source": [
            "interpreter = tf.lite.Interpreter(model_path=tflite_save_path)\n",
            "interpreter.allocate_tensors()"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 19,
        "metadata": {},
        "outputs": [],
        "source": [
            "# Get input and output tensors\n",
            "input_details = interpreter.get_input_details()\n",
            "output_details = interpreter.get_output_details()"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 20,
        "metadata": {},
        "outputs": [],
        "source": [
            "interpreter.set_tensor(input_details[0]['index'], np.array([X_test[0]]))"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 21,
        "metadata": {
            "scrolled": true
        },
        "outputs": [
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "Wall time: 0 ns\n"
                ]
            }
        ],
        "source": [
            "%%time\n",
            "# Perform inference\n",
            "interpreter.invoke()\n",
            "tflite_results = interpreter.get_tensor(output_details[0]['index'])"
        ]
    },
    {
        "cell_type": "code",
        "execution_count": 22,
        "metadata": {},
        "outputs": [
            {
                "name": "stdout",
                "output_type": "stream",
                "text": [
                    "[0.7729778  0.16973573 0.05728643]\n",
                    "0\n"
                ]
            }
        ],
        "source": [
            "print(np.squeeze(tflite_results))\n",
            "print(np.argmax(np.squeeze(tflite_results)))"
        ]
    }
],
"metadata": {
    "kernelspec": {
        "display_name": "Python 3",
        "language": "python",
        "name": "python3"
    },
    "language_info": {
        "codemirror_mode": {
            "name": "ipython",
            "version": 3
        },
        "file_extension": ".py",
        "mimetype": "text/x-python",
        "name": "python",
        "nbconvert_exporter": "python",
        "pygments_lexer": "ipython3",
        "version": "3.8.5"
    }
},
"nbformat": 4,
"nbformat_minor": 4
}